package utils

import (
	"math"
)

var Vec2One Vec2 = Vec2{1, 1}
var Vec2Zero Vec2 = Vec2{0, 0}

//	A 2-dimensional vector.
type Vec2 struct{ X, Y float64 }

//	Returns a new `*Vec2` that is the result of dividing `me` by `vec`.
func (me *Vec2) Div(vec *Vec2) *Vec2 {
	return &Vec2{me.X / vec.X, me.Y / vec.Y}
}

//	Returns the dot product of `me` and `vec`.
func (me *Vec2) Dot(vec *Vec2) float64 {
	return (me.X * vec.X) + (me.Y * vec.Y)
}

//	Returns the 2D vector length of `me`.
func (me *Vec2) Length() float64 {
	return math.Sqrt((me.X * me.X) + (me.Y * me.Y))
}

//	Returns the 2D vector magnitude of `me`.
func (me *Vec2) Magnitude() float64 {
	return math.Sqrt(me.Length())
}

//	Returns a new `*Vec2` that is the result of multiplying `me` with `vec`.
func (me *Vec2) Mult(vec *Vec2) *Vec2 {
	return &Vec2{me.X * vec.X, me.Y * vec.Y}
}

//	Normalizes `me` in-place.
func (me *Vec2) Normalize() {
	// l := 1 / me.Magnitude()
	// me.X, me.Y = me.X*l, me.Y*l
	me.Scale(1 / me.Magnitude())
}

//	Returns a new `*Vec2` that is the normalized representation of `me`.
func (me *Vec2) Normalized() *Vec2 {
	return me.Scaled(1 / me.Magnitude())
	// l := 1 / me.Magnitude()
	// return Vec2{me.X * l, me.Y * l}
}

//	Returns a new `*Vec2` that is the normalized representation of `me` scaled by `factor`.
func (me *Vec2) NormalizedScaled(factor float64) (vec *Vec2) {
	vec = me.Normalized()
	vec.Scale(factor)
	return
	// l := 1 / me.Magnitude()
	// return Vec2{me.X * l * factor, me.Y * l * factor}
}

//	Multiplies all components in `me` with `factor`.
func (me *Vec2) Scale(factor float64) {
	me.X, me.Y = me.X*factor, me.Y*factor
}

//	Returns a new `*Vec2` that represents `me` scaled by `factor`.
func (me *Vec2) Scaled(factor float64) *Vec2 {
	return &Vec2{me.X * factor, me.Y * factor}
}

//	Returns a human-readable (imprecise) `string` representation of `me`.
func (me *Vec2) String() string {
	return strf("{X:%1.2f Y:%1.2f}", me.X, me.Y)
}

//	Returns a new `*Vec2` that represents `me` minus `vec`.
func (me *Vec2) Sub(vec *Vec2) *Vec2 {
	return &Vec2{me.X - vec.X, me.Y - vec.Y}
}

func (me *Vec2) Add(vec *Vec2) {
	me.X, me.Y = me.X+vec.X, me.Y+vec.Y
}

// Rotated returns a counter-clockwise rotated copy of the vector.
func (vec *Vec2) Rotated(angle float32) Vec2 {
	sinus := math.Sin(float64(angle))
	cosinus := math.Cos(float64(angle))
	return Vec2{
		vec.X*cosinus - vec.Y*sinus,
		vec.X*sinus + vec.Y*cosinus,
	}
}

func (this *Vec2) Rotate(angle float32) {
	*this = this.Rotated(angle)
}
